package com.inspectortime.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.xml.SAXErrorHandler;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public final class XMLUtils {

	    private XMLUtils() {
	    }

	    public static Element findElementByAttributeValue(Element elem, String tagName, String attrName, String attrValue) {
	        List list = elem.elements(tagName);
	        if (list.isEmpty()) {
	            throw new RuntimeException("No child element '" + tagName + "' found in node: " + elem);
	        }
	        for (Iterator it = list.iterator(); it.hasNext();) {
	            Element childElem = (Element) it.next();
	            String value = childElem.attributeValue(attrName);
	            if (value != null && value.equals(attrValue)) {
	                return childElem;
	            }
	        }
	        throw new RuntimeException("No child element '" + tagName + "' with attribute " + attrName + "="
	                + attrValue + " found in node: " + elem);
	    }

	    /**
	     * Looks up an element by the value of one or more of its attributes
	     * 
	     * @param parentElem
	     *            parent element
	     * @param tagName
	     *            name of child element inside parent element
	     * @param attributeNameValuePairs
	     *            list of attribute names and value pairs to search
	     * @return the matching element, or null if none found
	     */
	    public static Element findElementByAttributeValues(Element parentElem, String tagName,
	            Map attributeNameValuePairs) {
	        List list = parentElem.elements(tagName);
	        if (list.isEmpty()) {
	            return null;
	        }
	        for (Iterator it = list.iterator(); it.hasNext();) {
	            Element childElem = (Element) it.next();

	            // Check if all attributes match
	            boolean match = true;
	            Iterator paramIt = attributeNameValuePairs.keySet().iterator();
	            while (paramIt.hasNext()) {
	                String paramName = (String) paramIt.next();
	                String paramValue = (String) attributeNameValuePairs.get(paramName);
	                String value = childElem.attributeValue(paramName);
	                if (value != null && value.equals(paramValue)) {
	                    // Do nothing, keep the match=true value
	                } else {
	                    match = false;
	                }
	            }
	            if (match) {
	                return childElem;
	            }
	        }
	        return null;
	    }

	    /**
	     * Load an XML Document from a given absolute file path
	     * 
	     * @param xmlFile
	     * @return document
	     * @throws RegistrationRuntimeException
	     *             if file can't be found
	     */
	    public static Document load(File xmlFile) {
	        InputStream in = null;
	        try {
	            in = new FileInputStream(xmlFile);
	        } catch (FileNotFoundException e) {
	            throw new RuntimeException("File not found: " + e.getMessage(), e);
	        }
	        return load(xmlFile.getAbsolutePath(), in);
	    }

	    /**
	     * Load an XML Document from an inputstream without validating it
	     * 
	     * @param id
	     * @param in
	     * @return the loaded <code>Document</code>
	     */
	    public static Document load(String id, InputStream in) {
	        return load(id, in, false);
	    }

	    /**
	     * Load an XML Document from an inputstream
	     * 
	     * @param id used for error messaging only
	     * @param in
	     * 
	     * @param isValidateEnabled
	     *            whether or not the parser should validate the XML file against
	     *            a DTD (if specified)
	     * @return the loaded <code>Document</code>
	     */
	    public static Document load(String id, InputStream in, boolean isValidateEnabled) {
	        SAXReader reader = new SAXReader(isValidateEnabled);
	        reader.setErrorHandler(new SAXErrorHandler());
	        reader.setEntityResolver(new ClassPathEntityResolver());
	        try {
	            return reader.read(in);
	        } catch (DocumentException e) {
	            throw new RuntimeException("Could not parse " + id, e);
	        }
	    }

}
